package cn.rtplay.esp32camcar.GearSeekBar;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import cn.rtplay.esp32camcar.R;
import cn.rtplay.esp32camcar.toolUtils.LogUtil;

/**
 * 自定义档位SeekBar ViewGroup
 * Created by Jaceli on 2016-04-28.
 */
public class GearSeekBarParent extends FrameLayout {

    private PointF pointFt1;
    private PointF pointFt2;
    private PointF pointFt3;
    private PointF pointFt4;
    private PointF pointFt5;
    private PointF pointFt6;
    private PointF pointFt7;
    private PointF pointFt8;
    private PointF pointFt0;
    private PointF circleCenter;                // 球的坐标
    private int currentLevel = 0;               // 当前档次
    private int lastLevel = 0;                  // 最后的档位，用于经过档位去重判断

    private OnProgressChangedListener listener; // 档次改变的监听
    private OnProgressTempChangedListener tempListener; // 档位经过时改变的监听
    private Context context;

    private SeekBarBallView ball;               // 球
    private SeekBarArcView arc;                 // 弧
    private int ballSize;                       // 球的大小
    private int arcWidth;                       // 弧的宽度
    private int arcColor;                       // 弧的颜色
    private Drawable ballBackground;            // 球的背景

    public GearSeekBarParent(Context context) {
        super(context);
        init();
    }

    public GearSeekBarParent(Context context,
                             AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        TypedArray array =
                context.obtainStyledAttributes(attrs, R.styleable.GearSeekBarParent);
        ballSize =
                array.getDimensionPixelSize(R.styleable.GearSeekBarParent_ballSize, 90);
        arcWidth =
                array.getDimensionPixelSize(R.styleable.GearSeekBarParent_arcWidth, 10);
        arcColor =
                array.getColor(R.styleable.GearSeekBarParent_arcColor, Color.BLACK);
        ballBackground = array.getDrawable(R.styleable.GearSeekBarParent_ballBackground);
        array.recycle();
        init();
    }

    private void init() {
        circleCenter = new PointF();

        // 添加弧线View
        arc = new SeekBarArcView(context, arcColor, arcWidth);
        arc.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        addView(arc);

        // 添加球View
        ball = new SeekBarBallView(context, ballSize, ballBackground);
        ball.setListener(this::changeBallLayout);
        addView(ball);
        // 从SeekBarArcView对象中获取坐标点，避免路线与轨迹不一致问题
        pointFt1 = arc.getPointFt1();
        pointFt2 = arc.getPointFt2();
        pointFt3 = arc.getPointFt3();
        pointFt4 = arc.getPointFt4();
        pointFt5 = arc.getPointFt5();
        pointFt6 = arc.getPointFt6();
        pointFt7 = arc.getPointFt7();
        pointFt8 = arc.getPointFt8();
        pointFt0 = arc.getPointFt0();
    }

    // 设置最终档位监听
    public void setListener(OnProgressChangedListener listener) {
        this.listener = listener;
    }

    // 设置路过档位监听
    public void setTempListener(OnProgressTempChangedListener listener) {
        this.tempListener = listener;
    }

    @Override
    protected void onLayout(boolean changed,
                            int left, int top,
                            int right,
                            int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        // 设置初始档位，默认档位是0
        changeBallLayout((int) pointFt0.x, (int) pointFt0.y);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                float downX = event.getX();
                float downY = event.getY();
                float distance =
                        (downX - circleCenter.x) * (downX - circleCenter.x) + (downY - circleCenter.y) * (downY - circleCenter.y);
                // 计算到圆球中心的距离，考虑20的误差，也就是在球的边缘再+20就可以按住
                return !(distance - ((float) ball.getMeasuredWidth() / 2 + 20) * ((float) ball.getMeasuredWidth() / 2 + 20) > 0);
            case MotionEvent.ACTION_MOVE:
                // 当手指移动时，使球跟手，不停地描画球的位置
                changeBallLayout((int) event.getX(), (int) event.getY());
                // 当手指移动时，计算经过的档位并更新经过档位
                currentLevel = getLevel(event);
                if (lastLevel != currentLevel) {
                    lastLevel = currentLevel;
                    if (tempListener != null) {
                        tempListener.OnProgressTempChanged(currentLevel);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                // 当手指离开View时，圆球平滑滑到最近的档次
                currentLevel = getLevel(event);
                int x;
                int y = (int) event.getY();
                if (currentLevel == 1) {
                    x = (int) pointFt1.x;
                    ball.smoothScrollLevel(x, y, 0, (int) (pointFt1.y - y));
                } else if (currentLevel == 2) {
                    x = (int) pointFt1.x;
                    ball.smoothScrollLevel(x, y, 0, (int) (pointFt2.y - y));
                } else if (currentLevel == 3) {
                    x = (int) pointFt3.x;
                    ball.smoothScrollLevel(x, y, 0, (int) (pointFt3.y - y));
                } else if (currentLevel == 0) {
                    x = (int) pointFt3.x;
                    ball.smoothScrollLevel(x, y, 0, (int) (pointFt0.y - y));
                } else if (currentLevel == 4) {
                    x = (int) pointFt3.x;
                    ball.smoothScrollLevel(x, y, 0, (int) (pointFt4.y - y));
                } else if (currentLevel == 5) {
                    x = (int) pointFt5.x;
                    ball.smoothScrollLevel(x, y, 0, (int) (pointFt5.y - y));
                } else if (currentLevel == 6) {
                    x = (int) pointFt5.x;
                    ball.smoothScrollLevel(x, y, 0, (int) (pointFt6.y - y));
                }
                if (listener != null) {
                    listener.OnProgressChanged(currentLevel);
                }
                break;
            default:
                // 当手指移出View时，目前好像不会进入到这个case中
                LogUtil.d("TAG", "onTouchEvent default: " + event.getX() + "," + event.getY());
                if (listener != null) {
                    listener.OnProgressChanged(currentLevel);
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * 改变球的位置，将球在参数坐标处描画出来
     *
     * @param currentX 当前x坐标
     * @param currentY 当前Y坐标
     */
    private void changeBallLayout(int currentX, int currentY) {
        float x = currentX;
        float y = currentY;
        if ((x > (y + pointFt7.x - pointFt7.y)) && (x < (y + pointFt0.x - pointFt0.y)) && (x > (pointFt7.x + pointFt7.y - y)) && (x < (pointFt0.x + pointFt0.y - y))) {
            y = pointFt7.y;
        } else if ((x > (y + pointFt0.x - pointFt0.y)) && (x < (y + pointFt8.x - pointFt8.y)) && (x > (pointFt0.x + pointFt0.y - y)) && (x < (pointFt8.x + pointFt8.y - y))) {
            y = pointFt0.y;
        } else if (x < ((pointFt1.x + pointFt3.x) / 2)) {
            x = pointFt1.x;
        } else if (x < ((pointFt3.x + pointFt5.x) / 2)) {
            x = pointFt3.x;
        } else {
            x = pointFt5.x;
        }
        if (y < pointFt1.y) {
            y = pointFt1.y;
        }
        if (y > pointFt2.y) {
            y = pointFt2.y;
        }
        circleCenter.set(x, y);
        ball.layout((int) (x - ball.getMeasuredWidth() / 2),
                (int) (y - ball.getMeasuredWidth() / 2),
                (int) (x + ball.getMeasuredWidth() / 2),
                (int) (y + ball.getMeasuredWidth() / 2));
    }

    /**
     * 计算档次
     *
     * @param event 事件，可以得到坐标
     * @return 档次
     */
    private int getLevel(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        int result;
        if (x < ((pointFt1.x + pointFt3.x) / 2)) {
            if (y < pointFt7.y) {
                result = 1;
            } else {
                result = 2;
            }
        } else if (x < ((pointFt3.x + pointFt5.x) / 2)) {
            if (y < ((pointFt3.y + pointFt0.y) / 2)) {
                result = 3;
            } else if (y < ((pointFt0.y + pointFt4.y) / 2)) {
                result = 0;
            } else {
                result = 4;
            }
        } else {
            if (y < pointFt8.y) {
                result = 5;
            } else {
                result = 6;
            }
        }
        return result;
    }

    /**
     * 滑动接口
     */
    public interface OnProgressChangedListener {
        void OnProgressChanged(int level);
    }

    /**
     * 滑动接口
     */
    public interface OnProgressTempChangedListener {
        void OnProgressTempChanged(int level);
    }
}
